package com.example.everying.task;/*
 * 项目名称: everything
 * 文件名: UserStatisticsTask
 * 作者: 张泽阳
 * 日期: 2025/7/7
 * 描述:
 */

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.everying.model.entity.statistics.SystemActivityStats;
import com.example.everying.model.entity.statistics.UserActiveDaily;
import com.example.everying.model.entity.statistics.UserSession;
import com.example.everying.service.statistics.*;
import com.example.everying.service.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
public class UserStatisticsTask {
    @Autowired
    private UserSessionService userSessionService;

    @Autowired
    private SystemActivityStatsService systemActivityStatsService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserActiveDailyService userActiveDailyService;

    @Autowired
    private UserRetentionStatsService userRetentionStatsService;

    @Autowired
    private UserRetentionStatService userRetentionStatService;


    @Scheduled(cron = "0 0 * * * ?")
    @Transactional
    public void addSystemHourlyActivity() {
        log.info("开始更新用户每小时活跃度");

        LocalDateTime startTime = LocalDateTime.now()
                .truncatedTo(ChronoUnit.HOURS)
                .minusHours(1);
        LocalDateTime endTime  = startTime.plusMinutes(59);

        List<String> userIds = userSessionService.getUserIdsByTime(startTime, endTime);

        List<UserSession> userSessionList = userSessionService.list(new QueryWrapper<UserSession>()
                .ge("login_time", startTime)
                .le("login_time", endTime));

        long totalSecond = userSessionList.stream()
                .filter(session -> session.getLogoutTime() != null)
                .mapToLong(session ->
                        Duration.between(session.getLoginTime(), session.getLogoutTime()).getSeconds()
                )
                .sum();

        SystemActivityStats systemActivityStats = new SystemActivityStats();
        systemActivityStats.setStatDate(LocalDate.now());
        systemActivityStats.setHourSlot(LocalDateTime.now().getHour() - 1);
        systemActivityStats.setActiveUsers(userIds.size());
        systemActivityStats.setStatType(2);
        if (totalSecond > 0 && userIds.size() > 0){
            systemActivityStats.setAvgDuration((int) (totalSecond / userIds.size()));
        }
        systemActivityStats.setNewUsers(userService.getSignCount(startTime,endTime));
        systemActivityStats.setCreateTime(LocalDateTime.now());
        systemActivityStats.setUpdateTime(LocalDateTime.now());
        systemActivityStatsService.save(systemActivityStats);
        log.info("更新完成：{}", systemActivityStats);

    }

    @Scheduled(cron = "0 0 1 * * ?")
    @Transactional
    public void addSystemDailyActivity() {
        log.info("开始更新系统每日活跃度");
        LocalDateTime startTime = LocalDateTime.now()
                .truncatedTo(ChronoUnit.DAYS)
                .minusDays(1);
        LocalDateTime endTime  = startTime.plusDays(1);
        List<String> userIds = userSessionService.getUserIdsByTime(startTime, endTime);

        List<UserSession> userSessionList = userSessionService.list(new QueryWrapper<UserSession>()
                .ge("login_time", startTime)
                .le("login_time", endTime));

        long totalSecond = userSessionList.stream()
                .filter(session -> session.getLogoutTime() != null)
                .mapToLong(session ->
                        Duration.between(session.getLoginTime(), session.getLogoutTime()).getSeconds()
                )
                .sum();

        SystemActivityStats systemActivityStats = new SystemActivityStats();
        systemActivityStats.setStatDate(LocalDate.now().minusDays(1));
        systemActivityStats.setActiveUsers(userIds.size());
        systemActivityStats.setStatType(1);
        systemActivityStats.setAvgDuration((int) (totalSecond / userIds.size()));
        systemActivityStats.setNewUsers(userService.getSignCount(startTime,endTime));
        systemActivityStats.setCreateTime(LocalDateTime.now());
        systemActivityStats.setUpdateTime(LocalDateTime.now());
        systemActivityStatsService.save(systemActivityStats);

        log.info("开始更新用户每日活跃度");

        Map<String, UserActiveDaily> userActiveDailyMap = userSessionList.stream()
                        .filter(session -> session.getLogoutTime() != null)
                                .collect(Collectors.groupingBy(
                                        UserSession::getUserId,
                                        Collectors.collectingAndThen(
                                                Collectors.toList(),
                                                this::calculateDailyStats

                                        )
                                ));
        userActiveDailyMap.forEach((userId, dailyStats) -> {
            dailyStats.setUserId(userId);
            dailyStats.setCreateTime(LocalDateTime.now());
            dailyStats.setUpdateTime(LocalDateTime.now());
            dailyStats.setStatDate(LocalDate.now().plusDays(-1));
            userActiveDailyService.save(dailyStats);
        });
        log.info("更新完成：{}", systemActivityStats);

    }

    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    public void calculateDailyRetention(){
        log.info("开始计算用户每日留存");
        userRetentionStatService.addRetentionStat();
        log.info(" 已完成截至{}的用户留存统计", LocalDate.now().minusDays(1));

    }


    private UserActiveDaily calculateDailyStats(List<UserSession> userSessionList){
        UserActiveDaily userActiveDaily = new UserActiveDaily();

        // 计算登录次数
        userActiveDaily.setLoginCount(userSessionList.size());

        // 计算总时长
        long sum = userSessionList.stream()
                .filter(session -> session.getLogoutTime() != null)
                .mapToLong(session ->
                        Duration.between(session.getLoginTime(), session.getLogoutTime()).getSeconds()
                )
                .sum();

        userActiveDaily.setTotalDuration((int) sum);
        return userActiveDaily;
    }
}
